from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from typing import Tuple
import numpy as np
import random
import time

ROWS = 50
COLS = 50
cells = np.ndarray((ROWS, COLS), dtype=np.int16)

def drawFunc():    
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

    rows, cols = cells.shape
    w = 0.95 / rows * 2
    glPointSize(4)
    glBegin(GL_POINTS)
    for y in range(rows):
        for x in range(cols):
            if cells[y,x] > 0:
                a = np.array([0.01, -0.01, 0.0])
                b = np.array([0.0, 2.0, 0.0])
                rgb = cells[y,x] * a + b
            else:
                rgb = np.array([0.3, 0.3, 0.3])
            glColor3f(*rgb.tolist())
            glVertex2f((x - cols/2. +.5)*w, (rows/2.-y-.5)*w)
    glEnd()
    glFlush()
    glutSwapBuffers()
    time.sleep(0.03333)
    
def init_cells():
    num_of_cells = int(ROWS * COLS / 2)
    for i in range(num_of_cells):
            y = random.randrange(0, ROWS)
            x = random.randrange(0, COLS)
            cells[y, x] = 1
            
def count_live_neigbours(y:int, x:int) -> int:
    s = cells[max(0, y-1):y+2, max(0, x-1):x+2]
    return np.count_nonzero(s) - np.count_nonzero(cells[y,x])

def update():   
    rows, cols = cells.shape
    nb_count = np.ndarray((rows, cols), dtype=np.int16)
    for y in range(rows):
        for x in range(cols):
            nb_count[y, x] = count_live_neigbours(y, x)
    """
    “人口过少”：任何活细胞如果活邻居少于2个，则死掉。
    “正常”：任何活细胞如果活邻居为2个或3个，则继续活。
    “人口过多”：任何活细胞如果活邻居大于3个，则死掉。
    “繁殖”：任何死细胞如果活邻居正好是3个，则活过来。
    """
    cells[(cells>0) & (nb_count<2)] = 0
    # cells[(cells==1) & ((nb_count==2) | (nb_count==3))] = 1
    cells[(cells>0) & (nb_count>3)] = 0
    cells[(cells==0) & (nb_count==3)] = 1
    
    cells[cells>0] += 1
        
    
def idleFunc():
    update()
    
    drawFunc()

MENU_ITEM_RESTART = 1

def menu_callback(value:int):
    if value == MENU_ITEM_RESTART:
        init_cells()
    return True

def main():
    import sys
    
    glutInit()
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA)
    glutInitWindowSize(600, 600)
    glutCreateWindow("Life Game")
    glutCreateMenu(menu_callback)
    glutAddMenuEntry('Restart', MENU_ITEM_RESTART)
    glutAttachMenu(GLUT_RIGHT_BUTTON)
    
    init_cells()

    glutDisplayFunc(drawFunc)
    glutIdleFunc(idleFunc)
    glutMainLoop()
    
    
if __name__=='__main__':
    import sys
    sys.exit(main())
